// src/pages/booking/data.ts (Example data structure)
import dayjs from 'dayjs'; // Using dayjs for easier date manipulation and formatting
import 'dayjs/locale/zh-cn';
import LogUtils from "@/utils/log";
import Utils from "@/utils/common"; // Import Chinese locale for weekday names

// Ensure dayjs uses the Chinese locale globally or where needed
dayjs.locale('zh-cn');
export type AvailabilityData = Record<string, string[]>;


export interface DateTab {
  id: string; // e.g., '2024-04-25'
  title: string; // Formatted title for the tab
}

const formatYYMMDD = 'YYYY-MM-DD'
export default class DateUtils {
  //传入
  static getRecentDateTabs(startDateString: string, numberOfDays: number): DateTab[] {
    const resultTabs: DateTab[] = [];

    // Validate inputs
    if (!startDateString || numberOfDays < 1 || isNaN(numberOfDays)) {
      console.error("Invalid input: Provide a valid startDateString (YYYY-MM-DD) and a positive numberOfDays.");
      return resultTabs; // Return empty array for invalid input
    }

    const startDate = dayjs(startDateString);

    // Check if the start date is valid
    if (!startDate.isValid()) {
      console.error(`Invalid start date format: ${startDateString}. Please use YYYY-MM-DD.`);
      return resultTabs;
    }


    for (let i = 0; i < numberOfDays; i++) {
      const currentDate = startDate.add(i, 'day');
      const id = currentDate.format(formatYYMMDD);
      const weekday = currentDate.format('ddd'); // e.g., '周五'
      const monthDay = currentDate.format('MM-DD'); // e.g., '04月25日'
      const title = `(${weekday})\n${monthDay}`;
      resultTabs.push({id, title});
    }

    return resultTabs;
  }


  static getToday() {
    return dayjs().format(formatYYMMDD)
  }


  static generateTimeSlotsWithAvailabilityAndTimeCheck(
    dateString: string | null | undefined,
    availabilityData: AvailabilityData | null | undefined
  ): SelectTimeModel[] {
    const slots: SelectTimeModel[] = [];
    if (Utils.isNotBlank(availabilityData)) {
      LogUtils.info(availabilityData)
    }
    if (!dateString || !availabilityData) {
      console.error("generateTimeSlotsWithAvailabilityAndTimeCheck: Invalid dateString or availabilityData provided.");
      return slots; // Return empty for invalid input
    }

    const startOfDay = dayjs(dateString).startOf('day');

    if (!startOfDay.isValid()) {
      console.error(`generateTimeSlotsWithAvailabilityAndTimeCheck: Invalid date format: ${dateString}. Please use YYYY-MM-DD.`);
      return slots;
    }

    const now = dayjs();
    const availableSlotsForDate = availabilityData[dateString] || [];
    for (let i = 0; i < 48; i++) {
      const startTime = startOfDay.add(i * 30, 'minute');
      const endTime = startTime.add(30, 'minute');

      const startTimeFormatted = startTime.format('HH:mm');
      const endTimeFormatted = (endTime.hour() === 0 && endTime.minute() === 0)
        ? '24:00'
        : endTime.format('HH:mm');

      // Format the display text
      const text = `${startTimeFormatted} - ${endTimeFormatted}`;

      // Create a unique ID
      const id = `${dateString}_${startTimeFormatted.replace(':', '')}`;

      const isListedAsAvailable = availableSlotsForDate.includes(text);


      const isPast = endTime.isBefore(now);

      const isDisabled = !isListedAsAvailable;
      slots.push({
        id: id,
        text: text,
        // 过去的时间或者是不在可选时间段内
        disabled: isPast || !isDisabled
      });
    }
    return slots;
  }


  static formatTimeRangeWithDayjs(dateTimeString: string | null | undefined): string | null {
    if (!dateTimeString || dateTimeString.trim() === "") {
      console.warn("输入字符串为空或无效。");
      return null;
    }

    // 使用 dayjs 解析输入字符串
    // dayjs 对 "YYYY-M-D H:mm" 这样的格式通常有较好的原生支持
    const startDate = dayjs(dateTimeString);

    // 检查日期是否有效
    if (!startDate.isValid()) {
      console.warn(`无法解析日期时间字符串: "${dateTimeString}"`);
      return null;
    }

    // 计算结束时间（开始时间后推30分钟）
    const endDate = startDate.add(30, 'minute');

    // 格式化日期部分 (从 startDate 获取，因为我们通常认为时间段属于开始的那一天)
    const datePart = startDate.format('YYYY-MM-DD');

    // 格式化开始时间部分
    const startTimePart = startDate.format('HH:mm');

    // 格式化结束时间部分
    const endTimePart = endDate.format('HH:mm');

    // 检查是否跨天 (可选的警告，行为与之前一致)
    if (startDate.format('YYYY-MM-DD') !== endDate.format('YYYY-MM-DD')) {
      // console.warn(`注意：计算出的结束时间 (${endDate.format('YYYY-MM-DD HH:mm')}) 已跨天。当前输出将使用开始日期 ${datePart}。`);
    }

    return `${datePart} ${startTimePart}-${endTimePart}`;
  }


  static convertSlotIdToDescription(combinedId: string | null | undefined): string | null {
    if (!combinedId || !combinedId.includes('_')) {
      console.error(`Invalid combinedId format: Expected 'YYYY-MM-DD_HHmm', received: ${combinedId}`);
      return null; // Return null for invalid or improperly formatted input
    }

    const parts = combinedId.split('_');
    if (parts.length !== 2) {
      console.error(`Invalid combinedId format: Expected one underscore separator, received: ${combinedId}`);
      return null;
    }

    const datePart = parts[0]; // "2025-04-27"
    const timePart = parts[1]; // "0000"

    // Validate date part format (basic check)
    if (!/^\d{4}-\d{2}-\d{2}$/.test(datePart)) {
      console.error(`Invalid date part format in ID: ${datePart}. Expected YYYY-MM-DD.`);
      return null;
    }

    // Validate time part format (HHmm)
    if (!/^\d{4}$/.test(timePart) || timePart.length !== 4) {
      console.error(`Invalid time part format in ID: ${timePart}. Expected HHmm.`);
      return null;
    }

    const hours = timePart.substring(0, 2);
    const minutes = timePart.substring(2, 4);

    // Construct an ISO-like string for reliable parsing
    const isoStartString = `${datePart}T${hours}:${minutes}:00`;
    const startTime = dayjs(isoStartString);

    // Check if parsing was successful
    if (!startTime.isValid()) {
      console.error(`Could not parse date/time from ID: ${combinedId}`);
      return null;
    }

    // Calculate end time (30 minutes later)
    const endTime = startTime.add(30, 'minute');

    // Format start and end times
    const startTimeFormatted = startTime.format('HH:mm');
    // Handle the 24:00 edge case
    const endTimeFormatted = (endTime.hour() === 0 && endTime.minute() === 0)
      ? '24:00'
      : endTime.format('HH:mm');

    // Combine into the final string
    return `${datePart} ${startTimeFormatted}-${endTimeFormatted}`;
  }


  static formatDateTimeArray(inputArray) {
    if (!Array.isArray(inputArray)) {
      console.error("输入必须是一个数组！");
      return ""; // 或者抛出错误 throw new Error("输入必须是一个数组！");
    }

    const formattedStrings = inputArray.map(dateTimeStr => {
      if (typeof dateTimeStr !== 'string' || dateTimeStr.indexOf('_') === -1) {
        console.warn(`跳过无效的字符串格式: ${dateTimeStr}`);
        return null; // 或者返回原始字符串，或者跳过
      }

      // 分割日期和时间部分
      const parts = dateTimeStr.split('_');
      const datePart = parts[0];
      const timePart = parts[1];

      // 格式化时间部分 (HHMM -> HH:MM)
      if (timePart && timePart.length === 4) {
        const formattedTime = `${timePart.substring(0, 2)}:${timePart.substring(2, 4)}`;
        return `${datePart} ${formattedTime}`;
      } else {
        console.warn(`跳过无效的时间格式: ${timePart} in ${dateTimeStr}`);
        return null; // 或者返回原始字符串，或者跳过
      }
    });

    // 过滤掉处理过程中可能产生的 null 值，然后用逗号连接
    return formattedStrings.filter(s => s !== null).join(',');
  }

  // 辅助函数：将数字格式化为两位数（例如 5 -> "05"）
  static pad(num: number): string {
    return num < 10 ? '0' + num : String(num);
  }

  /**
   * 使用 dayjs 解析日期时间字符串并返回一个 Date 对象。
   * dayjs 能够自动识别多种常见日期时间格式。
   * @param dateString 要解析的日期时间字符串
   * @param format (可选) 如果你知道确切的格式，提供它可以提高解析的准确性和性能。
   *                 例如："YYYY-MM-DD HH:mm:ss", "YYYY/M/D H:m"
   * @returns 解析成功则返回 Date 对象，否则返回 null
   */
  static parseDateWithDayjs(
    dateString: string | null | undefined,
    format?: string | string[] // 可以是一个格式字符串，或一个格式数组让 dayjs 依次尝试
  ): Date | null {
    if (!dateString || dateString.trim() === "") {
      // dayjs(null) 或 dayjs(undefined) 或 dayjs('') 也会是无效日期，
      // 但提前处理可以避免不必要的 dayjs 对象创建
      console.warn("parseDateWithDayjs: Input string is empty or invalid.");
      return null;
    }

    let djsObject: dayjs.Dayjs;

    if (format) {
      // 如果提供了格式字符串(或数组)，使用它进行解析
      // 需要 customParseFormat 插件才能使用第二个参数的 format
      // 如果没有 customParseFormat 插件，dayjs(dateString, format) 的行为可能不同或无效
      // 确保如果使用 format 参数，已经 extend 了 customParseFormat
      // dayjs.extend(customParseFormat); // 最好在应用入口处或 dayjs 工具模块顶部执行一次
      djsObject = dayjs(dateString, format, true); // 第三个参数 true 表示严格模式解析
    } else {
      // 如果没有提供格式，让 dayjs 自动尝试识别
      // dayjs 对 ISO 8601 和 RFC 2822 格式以及其他一些常见格式有很好的支持
      // 例如 "YYYY-MM-DD HH:mm:ss", "YYYY-MM-DDTHH:mm:ssZ", "YYYY/MM/DD"
      djsObject = dayjs(dateString);
    }

    if (djsObject.isValid()) {
      return djsObject.toDate(); // 转换为原生的 Date 对象
    } else {
      console.warn(`parseDateWithDayjs: Failed to parse date string "${dateString}"${format ? ` with format "${format}"` : ''}.`);
      return null;
    }
  }

// 辅助函数：将 Date 对象格式化为 YYYY-MM-DD
  static formatDate(date: Date): string {
    const year = date.getFullYear();
    const month = DateUtils.pad(date.getMonth() + 1); // 月份是从0开始的
    const day = DateUtils.pad(date.getDate());
    return `${year}-${month}-${day}`;
  }

  static formatSlotToString2(slot) {
    return `${slot.start.format('YYYY-MM-DD HH:mm')}-${slot.end.format('HH:mm')}`;
  }
  static formatSlotToString(slot) {
    const startTime = slot.start.format('YYYY-MM-DD HH:mm');
    let endTime = slot.end.format('HH:mm');
    // 判断 endTime 是否为 00:00，若是则替换为 24:00
    if (endTime === '00:00') {
      endTime = '24:00';
    }
    return `${startTime}-${endTime}`;
  }

  static getHours(dateTimeArray:string|null|undefined){
    //2025-05-24 19:00,2025-05-24 19:30,2025-05-24 18:00
    //需要判断dateTimeArray有可能为null,undeine
    if(dateTimeArray === null || dateTimeArray === undefined){
      return 0;
    }
    //获取长度并除以2
    const length = dateTimeArray.split(',').length;
    return length/2;
  }


  /**
   * 将日期时间字符串数组转换为带结束时间的范围字符串数组，并合并连续的时间段。
   * 每个结束时间是对应开始时间后推30分钟。
   *
   * @param {string[]} dateTimeArray - 日期时间字符串数组，例如 ["2025-05-24 19:00", ...]
   * @returns {string[]} 格式化并合并后的时间范围字符串数组，例如 ["2025-05-24 19:00-20:30", ...]
   */
  static formatAndMergeDateTimeRanges(dateTimeArray): DateTimeType[] {
    if (typeof dateTimeArray === 'string') {
      dateTimeArray = dateTimeArray.split(',');
    }
    if (!Array.isArray(dateTimeArray) || dateTimeArray.length === 0) {
      return [];
    }
    // 1. 将字符串转换为 Day.js 对象，并计算结束时间
    const slots = dateTimeArray
      .map(dateTimeStr => {
        const startTime = dayjs(dateTimeStr);
        if (!startTime.isValid()) {
          console.warn(`无效的日期时间字符串: ${dateTimeStr}`);
          return null; // 标记为null，稍后过滤
        }
        const endTime = startTime.add(30, 'minute');
        return {start: startTime, end: endTime, original: dateTimeStr};
      })
      .filter(slot => slot !== null); // 过滤掉无效的日期

    if (slots.length === 0) {
      return [];
    }

    // 2. 按开始时间排序 (非常重要)
    slots.sort((a, b) => a.start.valueOf() - b.start.valueOf());

    // 3. 合并连续的时间段
    const mergedSlots = [];
    if (slots.length > 0) {
      let currentMergedSlot = {...slots[0]}; // 深拷贝第一个作为当前合并段的开始

      for (let i = 1; i < slots.length; i++) {
        const nextSlot = slots[i];
        // 检查当前合并段的结束时间是否与下一个时段的开始时间完全相同
        // 并且它们必须是同一天 (虽然通常排序后同一天的会在一起，但明确检查更安全)
        if (currentMergedSlot.end.isSame(nextSlot.start) &&
          currentMergedSlot.start.isSame(nextSlot.start, 'day')) { // 确保是同一天
          // 如果连续，则扩展当前合并段的结束时间
          currentMergedSlot.end = nextSlot.end;
        } else {
          // 如果不连续，或者跨天了(虽然isSame会处理这个，但明确一下)，则将当前合并段添加到结果中
          mergedSlots.push(DateUtils.formatSlotToString(currentMergedSlot));
          currentMergedSlot = {...nextSlot};
        }
      }
      // 将最后一个合并段添加到结果中
      mergedSlots.push(DateUtils.formatSlotToString(currentMergedSlot));
    }
    return mergedSlots.map(slot => {
      const [date, time] = slot.split(' ');
      return {date, time};
    });
  }

// 辅助函数：将 Date 对象格式化为 HH:mm
  static formatTime(date: Date): string {
    const hours = DateUtils.pad(date.getHours());
    const minutes = DateUtils.pad(date.getMinutes());
    return `${hours}:${minutes}`;
  }

  static transformDateTimeString(input: string | null | undefined): DateTimeType[] {
    if (!input || input.trim() === "") {
      return [];
    }
    // 1. 分割字符串并去除首尾空格，过滤掉空字符串
    const dateTimeStrings = input
      .split(',')
      .map(s => s.trim())
      .filter(s => s.length > 0);

    if (dateTimeStrings.length === 0) {
      return [];
    }

    // 2. 将字符串转换为 Date 对象
    //    并过滤掉无效的日期时间字符串（如果 new Date() 解析失败会返回 Invalid Date）
    const parsedDates = dateTimeStrings
      .map(str => this.parseDateWithDayjs(str)).filter((date): date is Date => date !== null)


    if (parsedDates.length === 0) {
      console.warn("输入字符串中没有有效的日期时间条目。");
      return [];
    }

    // 3. 按时间先后顺序排序 Date 对象
    parsedDates.sort((a, b) => a.getTime() - b.getTime());

    // 4. 遍历排序后的 Date 对象，生成结果数组
    return parsedDates.map(startDate => {
      const dateStr = DateUtils.formatDate(startDate);
      const startTimeStr = DateUtils.formatTime(startDate);

      // 计算结束时间（开始时间后推30分钟）
      const endDate = new Date(startDate.getTime()); // 创建一个新的 Date 对象副本进行修改
      endDate.setMinutes(startDate.getMinutes() + 30);
      const endTimeStr = DateUtils.formatTime(endDate);

      return {
        date: dateStr,
        time: `${startTimeStr}-${endTimeStr}`
      };
    });
  }


  static transformStringToGroupedAvailability(
    inputString: string | null | undefined
  ): AvailabilityData {
    const groupedResult: AvailabilityData = {};

    if (!inputString || inputString.trim() === "") {
      return groupedResult;
    }

    // 1. Split the input string into individual date-time entries
    const dateTimeEntries = inputString
      .split(',')
      .map(s => s.trim())
      .filter(s => s.length > 0); // Remove any empty strings

    if (dateTimeEntries.length === 0) {
      return groupedResult;
    }

    // 2. Parse each entry, generate the 30-minute slot, and group by date
    const parsedDateObjects: { originalDate: Date; dateKey: string; timeSlot: string }[] = [];

    for (const entry of dateTimeEntries) {
      const startDate = this.parseDateWithDayjs(entry);

      // Skip invalid date entries
      if (startDate == null) {
        console.warn(`Invalid date-time string skipped: ${entry}`);
        continue;
      }

      const dateKey = this.formatDate(startDate); // e.g., "2025-05-17"
      const startTimeStr = this.formatTime(startDate); // e.g., "16:00"

      // Calculate end time (30 minutes after start)
      const endDate = new Date(startDate.getTime());
      endDate.setMinutes(startDate.getMinutes() + 30);
      const endTimeStr = this.formatTime(endDate); // e.g., "16:30"

      let timeSlot = `${startTimeStr} - ${endTimeStr}`; // e.g., "16:00 - 16:30"
      if (startTimeStr === "23:30" && endTimeStr === "00:00") {
        timeSlot = "23:30 - 24:00";
      }
      parsedDateObjects.push({originalDate: startDate, dateKey, timeSlot});
    }

    // 3. Sort the parsed objects primarily by date, then by time slot start time
    // This ensures that when we push to arrays, they are in chronological order.
    parsedDateObjects.sort((a, b) => {
      if (a.dateKey < b.dateKey) return -1;
      if (a.dateKey > b.dateKey) return 1;
      // If dates are the same, sort by the original start time
      return a.originalDate.getTime() - b.originalDate.getTime();
    });

    for (const item of parsedDateObjects) {
      if (!groupedResult[item.dateKey]) {
        groupedResult[item.dateKey] = [];
      }
      // Prevent duplicate time slots for the same date (optional, based on requirements)
      // If the input "2025-05-17 16:00,2025-05-17 16:00" should only produce one "16:00-16:30"
      if (!groupedResult[item.dateKey].includes(item.timeSlot)) {
        groupedResult[item.dateKey].push(item.timeSlot);
      }
    }

    return groupedResult;
  }

  static getSelectTimes(intString: string) {
    //'2025-05-17 16:00,2025-05-17 16:00'
    const dateTabs = DateUtils.getRecentDateTabs(DateUtils.getToday(), 30);
    //把数据放到SelectTimeModel
    const list: SelectTimeModel[] = dateTabs.map(tab => {
      const slots = DateUtils.generateTimeSlotsWithAvailabilityAndTimeCheck(tab.id, DateUtils.transformStringToGroupedAvailability(intString));
      return {
        id: tab.id,
        text: tab.title,
        disabled: false,
        children: slots
      }
    })

    return list
  }
}


export interface SelectTimeModel {
  id: string; // e.g., '2024-04-25'
  text: string; // Formatted title for the tab
  disabled: boolean; // Formatted title for the tab
  children?: SelectTimeModel[]
}


export interface DateTimeType {
  date: string;
  time: string;
}
